```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spring依赖注入详解 | 技术小馆</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.6;
        }
        .serif {
            font-family: 'Noto Serif SC', serif;
        }
        .code-block {
            background: #f8f9fa;
            border-left: 4px solid #4f46e5;
            font-family: monospace;
            padding: 1rem;
            border-radius: 0.25rem;
            overflow-x: auto;
        }
        .section-card {
            transition: all 0.3s ease;
            border-radius: 0.5rem;
        }
        .section-card:hover {
            transform: translateY(-4px);
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
        }
        .diagram-container {
            background: white;
            padding: 2rem;
            border-radius: 0.5rem;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <div class="relative bg-gradient-to-r from-indigo-600 to-purple-600 py-24 px-4 sm:px-6 lg:px-8">
        <div class="max-w-5xl mx-auto text-center">
            <h1 class="text-4xl md:text-5xl font-bold text-white serif tracking-tight">Spring 依赖注入详解</h1>
            <p class="mt-6 text-xl text-indigo-100 max-w-3xl mx-auto">
                探索Spring框架中依赖注入的核心机制与最佳实践
            </p>
            <div class="mt-10 flex items-center justify-center space-x-4">
                <span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-indigo-100 text-indigo-800">
                    <i class="fas fa-code mr-2"></i> 设计模式
                </span>
                <span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-indigo-100 text-indigo-800">
                    <i class="fas fa-project-diagram mr-2"></i> 解耦
                </span>
                <span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-indigo-100 text-indigo-800">
                    <i class="fas fa-cogs mr-2"></i> Spring框架
                </span>
            </div>
        </div>
    </div>

    <!-- Main Content -->
    <div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
        <!-- Introduction -->
        <div class="bg-white p-8 rounded-xl shadow-md mb-12">
            <h2 class="text-3xl font-bold text-gray-900 serif mb-6">什么是依赖注入？</h2>
            <p class="text-lg text-gray-700 mb-6">
                依赖注入（Dependency Injection，DI）是Spring框架中实现对象之间依赖关系的方式。它通过将对象的依赖关系交由容器管理，从而实现对象之间的解耦和灵活性。
            </p>
            <div class="grid md:grid-cols-2 gap-8 mt-8">
                <div>
                    <h3 class="text-xl font-semibold text-gray-800 serif mb-4">传统方式的问题</h3>
                    <ul class="space-y-3 text-gray-700">
                        <li class="flex items-start">
                            <i class="fas fa-exclamation-circle text-red-500 mt-1 mr-2"></i>
                            <span>对象直接创建依赖对象，导致紧耦合</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-exclamation-circle text-red-500 mt-1 mr-2"></i>
                            <span>测试困难，难以模拟依赖</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-exclamation-circle text-red-500 mt-1 mr-2"></i>
                            <span>代码重复，维护成本高</span>
                        </li>
                    </ul>
                </div>
                <div>
                    <h3 class="text-xl font-semibold text-gray-800 serif mb-4">依赖注入的优势</h3>
                    <ul class="space-y-3 text-gray-700">
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                            <span>降低耦合度，提高代码灵活性</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                            <span>便于单元测试和模拟</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                            <span>统一管理对象生命周期</span>
                        </li>
                    </ul>
                </div>
            </div>
        </div>

        <!-- DI Methods -->
        <h2 class="text-3xl font-bold text-gray-900 serif mb-8 border-b pb-4">依赖注入的多种方式</h2>
        
        <!-- Constructor Injection -->
        <div class="section-card bg-white p-8 rounded-xl shadow-md mb-8">
            <div class="flex items-center mb-6">
                <div class="flex items-center justify-center w-12 h-12 rounded-full bg-indigo-100 text-indigo-600 mr-4">
                    <i class="fas fa-hammer text-xl"></i>
                </div>
                <h3 class="text-2xl font-bold text-gray-900 serif">构造函数注入</h3>
            </div>
            <p class="text-gray-700 mb-6">
                构造函数注入是通过对象的构造函数来注入依赖关系。在Spring框架中，可以通过配置文件或注解来指定构造函数参数的值，从而在创建对象时自动注入依赖。
            </p>
            <div class="code-block mb-4">
                <pre><code>public class C {
    private A a;
    private B b;
    
    public C(A a, B b) {
        this.a = a;
        this.b = b;
    }
}</code></pre>
            </div>
            <div class="grid md:grid-cols-2 gap-6 mt-6">
                <div>
                    <h4 class="font-semibold text-gray-800 mb-2">XML配置方式</h4>
                    <div class="code-block">
                        <pre><code>&lt;bean id="a" class="com.example.A"/&gt;
&lt;bean id="b" class="com.example.B"/&gt;
&lt;bean id="c" class="com.example.C"&gt;
    &lt;constructor-arg ref="a"/&gt;
    &lt;constructor-arg ref="b"/&gt;
&lt;/bean&gt;</code></pre>
                    </div>
                </div>
                <div>
                    <h4 class="font-semibold text-gray-800 mb-2">注解方式</h4>
                    <div class="code-block">
                        <pre><code>@Component
public class C {
    private final A a;
    private final B b;

    @Autowired
    public C(A a, B b) {
        this.a = a;
        this.b = b;
    }
}</code></pre>
                    </div>
                </div>
            </div>
            <div class="mt-6 p-4 bg-blue-50 rounded-lg border border-blue-200">
                <h4 class="font-semibold text-blue-800 flex items-center mb-2">
                    <i class="fas fa-lightbulb text-blue-500 mr-2"></i>
                    最佳实践建议
                </h4>
                <p class="text-blue-700">
                    构造函数注入是官方推荐的方式，特别是在Spring 4.3+版本中，对于单一构造函数的类，可以省略@Autowired注解。这种方式强制要求依赖不可为空，并且使依赖变为final，有利于不变性和线程安全。
                </p>
            </div>
        </div>

        <!-- Setter Injection -->
        <div class="section-card bg-white p-8 rounded-xl shadow-md mb-8">
            <div class="flex items-center mb-6">
                <div class="flex items-center justify-center w-12 h-12 rounded-full bg-purple-100 text-purple-600 mr-4">
                    <i class="fas fa-wrench text-xl"></i>
                </div>
                <h3 class="text-2xl font-bold text-gray-900 serif">Setter方法注入</h3>
            </div>
            <p class="text-gray-700 mb-6">
                Setter方法注入是通过对象的Setter方法来注入依赖关系。容器在创建对象后会调用相应的Setter方法来设置依赖。
            </p>
            <div class="code-block mb-4">
                <pre><code>public class C {
    private A a;
    private B b;
    
    @Autowired
    public void setA(A a) {
        this.a = a;
    }
    
    @Autowired
    public void setB(B b) {
        this.b = b;
    }
}</code></pre>
            </div>
            <div class="grid md:grid-cols-2 gap-6 mt-6">
                <div>
                    <h4 class="font-semibold text-gray-800 mb-2">XML配置方式</h4>
                    <div class="code-block">
                        <pre><code>&lt;bean id="c" class="com.example.C"&gt;
    &lt;property name="a" ref="a"/&gt;
    &lt;property name="b" ref="b"/&gt;
&lt;/bean&gt;</code></pre>
                    </div>
                </div>
                <div>
                    <h4 class="font-semibold text-gray-800 mb-2">适用场景</h4>
                    <ul class="text-gray-700 space-y-2">
                        <li class="flex items-start">
                            <i class="fas fa-check text-purple-500 mt-1 mr-2"></i>
                            <span>可选依赖（非必须的依赖项）</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-check text-purple-500 mt-1 mr-2"></i>
                            <span>需要在运行时重新配置的依赖</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-check text-purple-500 mt-1 mr-2"></i>
                            <span>循环依赖的情况</span>
                        </li>
                    </ul>
                </div>
            </div>
        </div>

        <!-- Field Injection -->
        <div class="section-card bg-white p-8 rounded-xl shadow-md mb-8">
            <div class="flex items-center mb-6">
                <div class="flex items-center justify-center w-12 h-12 rounded-full bg-green-100 text-green-600 mr-4">
                    <i class="fas fa-bolt text-xl"></i>
                </div>
                <h3 class="text-2xl font-bold text-gray-900 serif">字段注入</h3>
            </div>
            <p class="text-gray-700 mb-6">
                字段注入是通过直接注入对象的字段来实现依赖注入。这种方式代码简洁，但有一些限制和问题。
            </p>
            <div class="code-block mb-4">
                <pre><code>@Component
public class C {
    @Autowired
    private A a;
    
    @Autowired
    private B b;
}</code></pre>
            </div>
            <div class="grid md:grid-cols-2 gap-6 mt-6">
                <div>
                    <h4 class="font-semibold text-gray-800 mb-2">优点</h4>
                    <ul class="text-gray-700 space-y-2">
                        <li class="flex items-start">
                            <i class="fas fa-plus-circle text-green-500 mt-1 mr-2"></i>
                            <span>代码简洁，减少样板代码</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-plus-circle text-green-500 mt-1 mr-2"></i>
                            <span>易于阅读和维护</span>
                        </li>
                    </ul>
                </div>
                <div>
                    <h4 class="font-semibold text-gray-800 mb-2">缺点</h4>
                    <ul class="text-gray-700 space-y-2">
                        <li class="flex items-start">
                            <i class="fas fa-minus-circle text-red-500 mt-1 mr-2"></i>
                            <span>无法声明依赖为final</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-minus-circle text-red-500 mt-1 mr-2"></i>
                            <span>难以进行单元测试</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-minus-circle text-red-500 mt-1 mr-2"></i>
                            <span>隐藏依赖关系，不够明确</span>
                        </li>
                    </ul>
                </div>
            </div>
            <div class="mt-6 p-4 bg-yellow-50 rounded-lg border border-yellow-200">
                <h4 class="font-semibold text-yellow-800 flex items-center mb-2">
                    <i class="fas fa-exclamation-triangle text-yellow-500 mr-2"></i>
                    注意事项
                </h4>
                <p class="text-yellow-700">
                    虽然字段注入在开发中很常见，但Spring官方不再推荐这种方式。它违反了面向对象设计的单一职责原则，使代码更难测试和维护。建议在新项目中使用构造函数注入作为首选。
                </p>
            </div>
        </div>

        <!-- Annotation Injection -->
        <div class="section-card bg-white p-8 rounded-xl shadow-md mb-8">
            <div class="flex items-center mb-6">
                <div class="flex items-center justify-center w-12 h-12 rounded-full bg-red-100 text-red-600 mr-4">
                    <i class="fas fa-tag text-xl"></i>
                </div>
                <h3 class="text-2xl font-bold text-gray-900 serif">注解注入</h3>
            </div>
            <p class="text-gray-700 mb-6">
                Spring提供了多个注解来支持依赖注入，包括<code class="bg-gray-100 px-1 rounded">@Autowired</code>、<code class="bg-gray-100 px-1 rounded">@Resource</code>、<code class="bg-gray-100 px-1 rounded">@Inject</code>等，它们各有特点和使用场景。
            </p>
            
            <div class="overflow-x-auto">
                <table class="min-w-full divide-y divide-gray-200">
                    <thead class="bg-gray-50">
                        <tr>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">注解</th>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">来源</th>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">注入方式</th>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">是否必须</th>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">适用场景</th>
                        </tr>
                    </thead>
                    <tbody class="bg-white divide-y divide-gray-200">
                        <tr>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <div class="text-sm font-medium text-gray-900">@Autowired</div>
                            </td>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <div class="text-sm text-gray-500">Spring</div>
                            </td>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <div class="text-sm text-gray-500">按类型</div>
                            </td>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">是</span>
                            </td>
                            <td class="px-6 py-4 text-sm text-gray-500">
                                适用于大多数场景，Spring默认推荐
                            </td>
                        </tr>
                        <tr>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <div class="text-sm font-medium text-gray-900">@Resource</div>
                            </td>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <div class="text-sm text-gray-500">JSR-250</div>
                            </td>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <div class="text-sm text-gray-500">按名称</div>
                            </td>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">可选</span>
                            </td>
                            <td class="px-6 py-4 text-sm text-gray-500">
                                需要按名称注入时使用
                            </td>
                        </tr>
                        <tr>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <div class="text-sm font-medium text-gray-900">@Inject</div>
                            </td>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <div class="text-sm text-gray-500">JSR-330</div>
                            </td>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <div class="text-sm text-gray-500">按类型</div>
                            </td>
                            <td class="px-6 py-4 whitespace-nowrap">
                                <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">是</span>
                            </td>
                            <td class="px-6 py-4 text-sm text-gray-500">
                                需要与Java标准兼容时使用
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>

        <!-- Type vs Name Injection -->
        <div class="grid md:grid-cols-2 gap-8 mb-12">
            <div class="section-card bg-white p-8 rounded-xl shadow-md">
                <div class="flex items-center mb-6">
                    <div class="flex items-center justify-center w-12 h-12 rounded-full bg-blue-100 text-blue-600 mr-4">
                        <i class="fas fa-filter text-xl"></i>
                    </div>
                    <h3 class="text-2xl font-bold text-gray-900 serif">类型注入</h3>
                </div>
                <p class="text-gray-700 mb-6">
                    按照Bean的类型进行自动装配。当接口有多个实现时，需要配合<code class="bg-gray-100 px-1 rounded">@Qualifier</code>注解指定具体实现。
                </p>
                <div class="code-block">
                    <pre><code>@RestController
public class EmpController {
    // 按类型注入EmpService接口
    @Autowired
    private EmpService empService;
    
    // 当有多个实现时使用@Qualifier
    @Autowired
    @Qualifier("empServiceImpl2")
    private EmpService empService2;
}</code></pre>
                </div>
            </div>
            <div class="section-card bg-white p-8 rounded-xl shadow-md">
                <div class="flex items-center mb-6">
                    <div class="flex items-center justify-center w-12 h-12 rounded-full bg-indigo-100 text-indigo-600 mr-4">
                        <i class="fas fa-signature text-xl"></i>
                    </div>
                    <h3 class="text-2xl font-bold text-gray-900 serif">名称注入</h3>
                </div>
                <p class="text-gray-700 mb-6">
                    按照Bean的名称进行注入，使用<code class="bg-gray-100 px-1 rounded">@Resource</code>注解或XML配置中的bean ID来指定。
                </p>
                <div class="code-block">
                    <pre><code>@RestController
public class EmpController {
    // 按名称注入empService
    @Resource(name = "empServiceImpl1")
    private EmpService empService;
    
    // 也可以直接使用变量名匹配
    @Resource
    private EmpService empServiceImpl2;
}</code></pre>
                </div>
            </div>
        </div>

        <!-- Diagram Section -->
        <div class="section-card bg-white p-8 rounded-xl shadow-md mb-12">
            <h2 class="text-3xl font-bold text-gray-900 serif mb-6">依赖注入关系图</h2>
            <p class="text-gray-700 mb-6">
                以下图表展示了Spring依赖注入的核心概念和不同方式之间的关系。
            </p>
            <div class="diagram-container">
                <div class="mermaid">
                    graph TD
                        A[依赖注入] --> B[构造函数注入]
                        A --> C[Setter方法注入]
                        A --> D[字段注入]
                        A --> E[注解注入]
                        E --> F[@Autowired]
                        E --> G[@Resource]
                        E --> H[@Inject]
                        F --> I[按类型注入]
                        G --> J[按名称注入]
                        H --> I
                        style A fill:#4f46e5,color:white
                        style B fill:#8b5cf6,color:white
                        style C fill:#8b5cf6,color:white
                        style D fill:#8b5cf6,color:white
                        style E fill:#8b5cf6,color:white
                        style F fill:#a78bfa,color:white
                        style G fill:#a78bfa,color:white
                        style H fill:#a78bfa,color:white
                        style I fill:#c4b5fd,color:black
                        style J fill:#c4b5fd,color:black
                </div>
            </div>
        </div>

        <!-- Best Practices -->
        <div class="section-card bg-white p-8 rounded-xl shadow-md">
            <h2 class="text-3xl font-bold text-gray-900 serif mb-6">依赖注入最佳实践</h2>
            <div class="grid md:grid-cols-2 gap-8">
                <div>
                    <h3 class="text-xl font-semibold text-gray-800 serif mb-4">推荐做法</h3>
                    <ul class="space-y-4">
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-8 w-8 rounded-full bg-green-100 flex items-center justify-center mr-3">
                                <i class="fas fa-check text-green-500"></i>
                            </div>
                            <div>
                                <h4 class="font-medium text-gray-900">优先使用构造函数注入</h4>
                                <p class="text-gray-600 mt-1">特别是对于强制依赖项，这种方式使依赖关系更明确，并且支持不可变对象。</p>
                            </div>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-8 w-8 rounded-full bg-green-100 flex items-center justify-center mr-3">
                                <i class="fas fa-check text-green-500"></i>
                            </div>
                            <div>
                                <h4 class="font-medium text-gray-900">合理使用Set注入</h4>
                                <p class="text-gray-600 mt-1">对于可选依赖或需要运行时重新配置的依赖，可以使用Setter方法注入。</p>
                            </div>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-8 w-8 rounded-full bg-green-100 flex items-center justify-center mr-3">
                                <i class="fas fa-check text-green-500"></i>
                            </div>
                            <div>
                                <h4 class="font-medium text-gray-900">明确依赖关系</h4>
                                <p class="text-gray-600 mt-1">使用<code class="bg-gray-100 px-1 rounded">@Qualifier</code>或<code class="bg-gray-100 px-1 rounded">@Resource</code>在有多实现时明确指定。</p>
                            </div>
                        </li>
                    </ul>
                </div>
                <div>
                    <h3 class="text-xl font-semibold text-gray-800 serif mb-4">避免做法</h3>
                    <ul class="space-y-4">
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-8 w-8 rounded-full bg-red-100 flex items-center justify-center mr-3">
                                <i class="fas fa-times text-red-500"></i>
                            </div>
                            <div>
                                <h4 class="font-medium text-gray-900">避免过度使用字段注入</h4>
                                <p class="text-gray-600 mt-1">虽然简洁，但隐藏了依赖关系，不利于测试和维护。</p>
                            </div>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-8 w-8 rounded-full bg-red-100 flex items-center justify-center mr-3">
                                <i class="fas fa-times text-red-500"></i>
                            </div>
                            <div>
                                <h4 class="font-medium text-gray-900">避免循环依赖</h4>
                                <p class="text-gray-600 mt-1">设计上应尽量避免，必要时可以使用Setter注入或<code class="bg-gray-100 px-1 rounded">@Lazy</code>。</p>
                            </div>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-8 w-8 rounded-full bg-red-100 flex items-center justify-center mr-3">
                                <i class="fas fa-times text-red-500"></i>
                            </div>
                            <div>
                                <h4 class="font-medium text-gray-900">避免混合多种注入方式</h4>
                                <p class="text-gray-600 mt-1">在同一个类中保持一致，避免同时使用构造器和字段注入。</p>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </div>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-12">
        <div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
            <div class="flex flex-col items-center">
                <div class="text-xl font-bold text-white mb-4 serif">技术小馆</div>
                <div class="mb-6">
                    <a href="http://www.yuque.com/jtostring" class="text-indigo-400 hover:text-indigo-300 transition duration-150 ease-in-out">
                        <i class="fas fa-globe mr-2"></i>http://www.yuque.com/jtostring
                    </a>
                </div>
                <div class="text-sm text-gray-500">
                    &copy; 2023 技术小馆. 保留所有权利.
                </div>
            </div>
        </div>
    </footer>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
    </script>
</body>
</html>
```